from unitproto import *
from protocol import *
from dev import *
from database import Database
from logger import log
from storage import Storage
from random import random
import time
import math
import gameengine
from planner import Planner

class Unit(UnitProto):
	def __init__(self, *kargs):
		UnitProto.__init__(self, *kargs)
		Object.__init__(self, 'girl1', 300, 200, 32, 32, None)
		self.authorized = False
		self.account = None
		self.character = None
		self.fps = 1
		self.away = False
		self.map = None
		self.visibleObjects = []

	def onConnect(self):
		self.write(Packet({'a':'auth-required'}))

	def onDisconnect(self):
		log('Handled user disconnect from %s'%self.ip)
		if self.authorized:
			self.map.removeUnit(self)
			self.dispatcher.broadcastEvent(Packet({'a':'out','nodeId':self.nodeId}), [self], self.map, self)

	def _updatePos(self):
		if self.authorized:
			Object._updatePos(self)

	def _updateVisibleObjects(self):
		if self.authorized:
			ins, outs = self.map.pollVisibility(self, self.visibleObjects)
			print ins
			print outs
			for item in ins:
				print item.__class__.__name__
#				if item is Unit:
#					type = 'player'
#				else:
#					type = 'object'
				self.write(Packet({'a':'in','object':item.name,'at':item.getPos(),'nodeId':item.nodeId,'texture':item.texture,'ms':item.ms,'name':item.name}))
				self.visibleObjects.append(item.nodeId)
			for item in outs:
				self.write(Packet({'a':'out','nodeId':item.nodeId}))
				self.visibleObjects.remove(item.nodeId)

	def processPacket(self, packet):
		try:
			if packet.a == 'ping':
				self.fps = packet.fps
				if self.fps < 10 and not self.away:	# User is away
					self.away = True
					self.dispatcher.broadcastEvent(Packet({'a':'away','nodeId':self.nodeId}))
				elif self.fps >= 10 and self.away: # User is back again
					self.away = False
					self.dispatcher.broadcastEvent(Packet({'a':'online','nodeId':self.nodeId}))
				pass
#				self.write(Packet({'a':'pingok'}))

			elif packet.a == 'auth':
				if self.authorized:
					raise AlreadyAuthorizedException

				account = Database().getAccount(packet.login, packet.password);

				if account:
					self.account = account
					self.nodeId = Storage().newId()
					textureColors = []
					for i in xrange(6):
						textureColors.append(int(random()*255))
					self.texture = './texture.php?h=%s,%s,%s&a=%s,%s,%s'%tuple(textureColors)
#					pack = Packet({'a':'auth','object':'girl1','name':self.account['login'],'nodeId':self.nodeId,'at':{'x':self.x,'y':self.y},'texture':'./texture.php?h=%s,%s,%s&a=%s,%s,%s'%tuple(self.texture),'map':'test','ms':self.ms})
					self.map = self.gameEngine.getMap('test')
					self.write(Packet({'a':'auth','object':'girl1','success':True,'name':self.account['login'],'nodeId':self.nodeId,'at':self.getPos(),'texture':self.texture,'map':'test','ms':self.ms}))
					log('User %s authorized as %s'%(self.ip, self.account['login']))
					self.dispatcher.broadcastEvent(Packet({'a':'in','type':'player','object':'girl1','nodeId':self.nodeId,'name':self.account['login'],'at':self.getPos(),'texture':self.texture,'map':'test','ms':self.ms}), [self], self.map, self)
#					for unit in self.dispatcher.getUnits():
#						if (unit.authorized) and (not (unit is self)):
#							self.visibleObjects.append(unit.nodeId)
#							self.write(Packet({'a':'in','type':'player','object':'girl1','nodeId':unit.nodeId,'name':unit.account['login'],'at':unit.getPos(),'texture':'./texture.php?h=%s,%s,%s&a=%s,%s,%s'%tuple(unit.texture),'ms':unit.ms}))
					self.authorized = True
					self.map.addUnit(self)
					self._updatePos()
					self._updateVisibleObjects()

				else:
					log('User %s failed to authorize as %s'%(self.ip, packet.login))
					self.write(Packet({'a':'auth','success':False}))
					self.authorized = False

			elif packet.a == 'message':
				if not self.authorized:
					raise UnauthorizedException

				self.dispatcher.broadcastEvent(Packet({'a':'message','sender':self.account['login'],'message':packet.message,'nodeId':self.nodeId}))

			elif packet.a == 'moveto':
				if not self.authorized:
					raise UnauthorizedException

				self._updatePos()
				self._updateVisibleObjects()

				self.moveStarted = time.time()
				# TODO!!!
				self.tx = packet.to['x']
				self.ty = packet.to['y']
				self.dispatcher.broadcastEvent(Packet({'a':'moveto','nodeId':self.nodeId,'from':{'x':self.x,'y':self.y},'to':packet.to}), [self])
				self.state = Object.IDLE

			elif packet.a == 'use-skill':
				if not self.authorized:
					raise UnauthorizedException

				dist = Storage().dist(self.getPos(), packet.to)
				if dist > 470:
					raise IllegalActionException

				tornadoId = Storage().newId()
				self.write(Packet({'a':'cooldown','skill':packet.skill,'cooldown':800}))
				self.dispatcher.broadcastEvent(Packet({'a':'in','object':'tornado','at':self.getPos(),'nodeId':tornadoId,'ms':200}), [], self.map, self);
				self.dispatcher.broadcastEvent(Packet({'a':'moveto','nodeId':tornadoId,'from':self.getPos(),'to':packet.to}), [], self.map, self);
				def done(time, tornadoId):
					self.dispatcher.broadcastEvent(Packet({'a':'out','nodeId':tornadoId}))
				Planner(done, dist / 200, tornadoId)

			else:
				# We received some bad packet
				raise WrongPacketException

		except WrongPacketException:
			log('Received bad action from %s'%self.ip)
			return self.disconnect()
		except UnauthorizedException:
			log('User from %s unauthorized to perform action `%s`'%(self.ip,packet.a))
			return self.disconnect()
		except AlreadyAuthorizedException:
			log('User from %s attempted to authorize again'%(self.ip))
			return self.disconnect()
		except IllegalActionException:
			log('User from %s attempted to CHEAT!!!'%(self.ip))
			return self.disconnect()
		except:
			raise

		return True

	def processEvent(self, event):
#		self.write(Packet({'a':'in','object':'','nodeId':self.nodeId}))
		if event.a == 'in' and event.nodeId not in self.visibleObjects:
			self.visibleObjects.append(event.nodeId)
		if event.a == 'out' and event.nodeId in self.visibleObjects:
			self.visibleObjects.remove(event.nodeId)
		self.write(event)
		return True
